#include "string_match.h"
#include "iot_debug.h"
#include "thirdparty/rapidjson/tools.h"
#include "version.h"
#include "sensormanager.h"
#include <logger.h>

std::string GetTime(void)
{
    std::string fmt;
    char linebuf[100] = {0};
    struct timespec tsCurr;
    struct tm tmCurr;
    int usCurr;
    clock_gettime(CLOCK_REALTIME, &tsCurr);
    localtime_r(&tsCurr.tv_sec, &tmCurr);
    usCurr = tsCurr.tv_nsec / 1000;
    sprintf(linebuf,"%04u-%02u-%02u %02u:%02u:%02u.%06u",
            tmCurr.tm_year + 1900,
            tmCurr.tm_mon + 1,
            tmCurr.tm_mday,
            tmCurr.tm_hour,
            tmCurr.tm_min,
            tmCurr.tm_sec,
            usCurr);
    fmt.append(linebuf);
    return fmt;
}

bool splitTcpDevice(const std::string &name, std::string &ip, uint32_t &port)
{
    std::string::size_type pos = name.find(':');
    if (pos > 7 && pos!=std::string::npos)
    {
        port = static_cast<uint32_t>(atoi(name.c_str()+pos+1));
        ip = name;
        ip.erase(ip.begin()+pos, ip.end());
        return true;
    }

    return false;
}

void stringTrim(std::string &str)
{
    if( !str.empty() )
    {
        str.erase(0, str.find_first_not_of(" "));
        str.erase(str.find_last_not_of(" ") + 1);
    }
}

bool splitRegNames(const std::string &reg, std::string &name, int &index1, int &index2)
{
    std::string tmp = reg;
    stringTrim(tmp);
    std::string::size_type pos = tmp.find('[');
    if (pos > 0 && pos!=std::string::npos)
    {
        name = tmp;
        name.erase(pos);
        tmp.erase(0, pos+1);

        pos = tmp.find(':');
        if (pos > 0 && pos!=std::string::npos)
        {
            index1 = atoi(tmp.c_str());
            tmp.erase(0, pos+1);

            pos = tmp.find(']');
            if (pos > 0 && pos!=std::string::npos)
            {
                index2 = atoi(tmp.c_str());
                tmp.erase(0, pos+1);
                return tmp.empty();
            }
        }
    }

    return false;
}

bool splitAttrCmdName(const std::string &name, std::string &id, std::string &str0, std::string &str1)
{
    std::string tmp(name);
    stringTrim(tmp);

    std::string::size_type pos = tmp.find('.');
    if (pos > 0 && pos!=std::string::npos)
    {
        id = tmp;
        id.erase(pos);
        tmp.erase(0, pos+1);

        pos = tmp.find('.');
        if (pos > 0 && pos!=std::string::npos)
        {
            str0 = tmp;
            str0.erase(pos);
            tmp.erase(0, pos+1);

            str1 = tmp;
            return true;
        }
    }
    return false;
}

std::string getThreadName()
{
    char name[128] = {0};
    pthread_t tid = pthread_self();

    name[sizeof(name) - 1] = '\0';

    return std::string(name);
}

std::string getVersion()
{
    return VERSION;
}

std::string getRuntime()
{
    return StartTime.c_str();
}

std::string getTrigger()
{
    return GetTime().c_str();
}

std::string translateTraceType(TraceType type)
{
    switch(type)
    {
        case E_NORMAL:
           return std::string("ERR_0_程序正常运行");

        case E_ACCESS:
            return std::string("ERR_1_访问文件失败");

        case E_LOADING:
            return std::string("ERR_2_加载系统配置失败");

        case E_CREATE:
            return std::string("ERR_3_创建设备失败");

        case E_DEVICE:
            return std::string("ERR_4_设备异常");

        case E_MODULE:
            return std::string("ERR_5_通讯模块异常");

        case E_PROGRAM:
            return std::string("ERR_6_程序异常");

        case E_COMMUNICATION:
            return std::string("ERR_7_通讯异常");

        default :
            return std::string("ERR_8_未知的异常情况");
    }
}

/*
名称: trace()
功能: 拼接生成一条异常跟踪信息
参数:
    Type        信息类型
    Desc        描述
    Reason      信息触发原因
    AlarmType   告警类型:0:消除告警；1:产生告警；2:刷新告警
返回: 异常跟踪信息
*/
const void trace(TraceType Type, std::string Desc, std::string Reason, int AlarmType)
{
    rapidjson::StringBuffer traceMsg;
    rapidjson::Writer<rapidjson::StringBuffer> writer(traceMsg);

    writer.StartObject();
    writer.Key("线程名称:");
    writer.String("Main");
    writer.Key("版本号:");
    writer.String(getVersion().c_str());
    writer.Key("运行时间:");
    writer.String(getRuntime().c_str());
    writer.Key("触发时间");
    writer.String(getTrigger().c_str());
    writer.Key("异常类型");
    writer.String(translateTraceType(Type).c_str());
    writer.Key("描述");
    writer.String(Desc.c_str());
    writer.Key("原因");
    writer.String(Reason.c_str());
    writer.EndObject();

    //写本地日志
    log_info("%s\n", traceMsg.GetString());
}

void Print_err_log(int err_code)
{
    TraceType Type;
    std::string Desc;
    std::string Reason;

    switch (err_code)
    {
        case OPEN_COMREMAP_FAIL:
            Type = E_ACCESS;
            Desc = "打开comRemap.json文件失败";
            Reason = "comRemap.json文件不存在或格式错误";
            break;

        case OPEN_COMSETTING_FAIL:
            Type = E_ACCESS;
            Desc = "打开comSetting.json文件失败";
            Reason = "comSetting.json文件不存在";
            break;

        case PARSE_COMSETTING_FAIL:
            Type = E_ACCESS;
            Desc = "访问comSetting.json文件失败";
            Reason = "comSetting.json格式错误";
            break;

        case OPEN_DEVLIST_FAIL:
            Type = E_ACCESS;
            Desc = "访问DevList.json文件失败";
            Reason = "DevList.json文件不存在";
            break;

        case PARSE_DEVLIST_FAIL:
            Type = E_ACCESS;
            Desc = "解析DevList.json文件失败";
            Reason = "DevList.json文件格式错误";
            break;

        case DEVLIST_IS_NULL:
            Type = E_LOADING;
            Desc = "解析DevList.json文件失败";
            Reason = "DevList.json文件内容为空";
            break;

        case OPEN_SOUTHDEVICELIST_FAIL:
            Type = E_ACCESS;
            Desc = "打开SouthDeviceList.json文件失败";
            Reason = "SouthDeviceList.json文件不存在";
            break;

        case PARSE_SOUTHDEVICELIST_FAIL:
            Type = E_LOADING;
            Desc = "解析SouthDeviceList.json文件失败";
            Reason = "SouthDeviceList.json文件内容为空或格式错误";
            break;

        case REGISTER_DEVICE_FAIL:
            Type = E_CREATE;
            Desc = "注册设备失败";
            Reason = "注册设备失败";
            break;

        case APP_IS_RUN:
            Type = E_PROGRAM;
            Desc = "应用程序已经在运行";
            Reason = "SyyGather已经在运行";
            break;

        case NOT_CONFIG_REGSTARTADDRPLC:
            Type = E_LOADING;
            Desc = "南向模型文件出错";
            Reason = "南向模型文件中使用白名单模型,但未配置RegStartAddrPLC字段";
            break;

        case NOT_CONFIG_WHITELIST:
            Type = E_LOADING;
            Desc = "DevList.json文件出错";
            Reason = "南向模型文件中使用白名单模型,但DevList.json文件中未配置WhiteList";
            break;

        case ALARM_IS_NORMAL:
            Type = E_NORMAL;
            Desc = "告警恢复";
            Reason = "程序正常运行";
            break;

        default:
            Type = E_PROGRAM;
            Desc = "其它";
            Reason = "其它异常情况导致程序退出";
            break;
    }

    if(err_code == ALARM_IS_NORMAL)
    {
        //告警恢复
        trace(Type, Desc, Reason, 0);
    }
    else
    {
        //产生告警
        trace(Type, Desc, Reason, 1);
    }

}

void Print_err_log_msg(int err_code, const char *err_msg)
{
    TraceType Type;
    std::string Desc;

    switch (err_code)
    {
        case DEVLIST_DEVID_REPEAT:
            Type = E_LOADING;
            Desc = "DevList.json文件中设备devID重复";
            break;

        case DEVLIST_INDEX_FAIL:
            Type = E_LOADING;
            Desc = "DevList.json中串口index错误";
            break;

        case MODE_FILE_NOTEXIST:
            Type = E_LOADING;
            Desc = "DevList.json中配置的南向模型文件不存在";
            break;

        case PARSE_MODE_FAIL:
            Type = E_LOADING;
            Desc = "解析南向模型文件失败";
            break;

        case MODE_TYPE_ERROR:
            Type = E_LOADING;
            Desc = "解析南向模型文件失败";
            break;

        case MODE_REGNAME_ERROR:
            Type = E_LOADING;
            Desc = "解析南向模型文件失败";
            break;

        case MODE_PROTOCOL_ERROR:
            Type = E_LOADING;
            Desc = "解析南向模型文件失败";
            break;

        case MODE_REGSIZE_ERROR:
            Type = E_LOADING;
            Desc = "解析南向模型文件失败";
            break;

        case PARSE_DATACENTERMODE_FAIL:
            Type = E_LOADING;
            Desc = "解析数据中心模型文件失败";
            break;

        case SOUTHDEVICELIST_DEVICE_IS_NULL:
            Type = E_LOADING;
            Desc = "SouthDeviceList.json文件中通过ComIndex及DevId查找对应的南向设备为空";
            break;

        case DATACENTERMODE_ITEM_IS_NULL:
            Type = E_LOADING;
            Desc = "SouthDeviceList.json文件数据中心属性名称为空";
            break;

        case SOUTHMODE_ITEM_IS_NULL:
            Type = E_LOADING;
            Desc = "SouthDeviceList.json文件南向属性名称为空";
            break;

        case REGISTER_MODE_FAIL:
            Type = E_CREATE;
            Desc = "注册模型文件失败";
            break;

        case REGISTER_UART_FAIL:
            Type = E_PROGRAM;
            Desc = "该串口被其它app占用";
            break;

        case READ_WHITELIST_FAIL:
            Type = E_MODULE;
            Desc = "读白名单数量错误";
            break;

        case SOUTHMODE_ITEM_IS_REPEAT:
            Type = E_LOADING;
            Desc = "数据中心设备项重复";
            break;

        case NOT_CONFIG_SERIALNUMBER:
            Type = E_LOADING;
            Desc = "南向模型文件中使用白名单模型,但DevList.json文件中未配置白名单";
            break;

        case SERIALNUMBER_SIZE_FAILE:
            Type = E_LOADING;
            Desc = "南向模型文件中使用白名单模型,但DevList.json文件中配置的白名单长度不符";
            break;

        default:
            break;
    }

    trace(Type, Desc, err_msg, 1);
}
